package com.sczmgk.hotline_pzh.db.base;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.sczmgk.hotline_pzh.annotation.Column;
import com.sczmgk.hotline_pzh.annotation.Count1;
import com.sczmgk.hotline_pzh.annotation.Count2;
import com.sczmgk.hotline_pzh.annotation.ID;
import com.sczmgk.hotline_pzh.annotation.Name1;
import com.sczmgk.hotline_pzh.annotation.Name2;
import com.sczmgk.hotline_pzh.annotation.OrderBy;
import com.sczmgk.hotline_pzh.annotation.TableName;
import com.sczmgk.hotline_pzh.annotation.Where;
import com.sczmgk.hotline_pzh.db.DBHelper;
import com.sczmgk.hotline_pzh.utils.MyLog;
import com.sczmgk.hotline_pzh.utils.Tools;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * 公有的方法
 * //1.表名的获取(也就是在bean上加入注解，注解)
 * //2.表中的列信息如何与实体的属性一一对应
 * //3.如何将实体中的数据设置给表
 * //4.如何获取主键的内容
 * //5.实体对应实例的创建
 */
public abstract class DAOSupport<M> implements DAO<M> {
    private Context context;
    //子类会用到
    protected SQLiteDatabase db;
    protected String TAG = this.getClass().getSimpleName();

    public DAOSupport(Context context) {
        db = DBHelper.getInstance(context).getWritableDatabase();
        this.context = context;
    }

    @Override
    public long insert(M m) {
        ContentValues values = fillConstantValues(m);

        return db.insert(getTableName(), null, values);

    }

    @Override
    public int delete(Serializable id) {
        return db.delete(getTableName(), DBHelper.TABLE_ID + "=?", new String[]{id + ""});
    }

    @Override
    public int deleteAll() {

        return db.delete(getTableName(),null,null);
    }

    @Override
    public int updata(M m) {
        ContentValues values = fillConstantValues(m);

        return db.update(getTableName(), values, DBHelper.TABLE_ID + "=?", new String[]{getId(m)});
    }


    @Override
    public int getCountByQuery(Serializable value) {
        Cursor cursor = db.query(getTableName(),null,getQueryField(),new String[]{value+""},null,null,null);
        if(cursor != null){
            return cursor.getCount();
        }
        return 0;
    }

    @Override
    public List<M> findAll() {
        Cursor cursor = db.query(getTableName(), null, null, null, null, null, null);
        if (cursor != null) {
            List<M> result = new ArrayList<M>();
            while (cursor.moveToNext()) {
                M instance = fillInstance(cursor);
                result.add(instance);
            }
            cursor.close();
            return result;
        }
        return null;
    }

    @Override
    public M findById(Serializable id) {
        Cursor cursor = db.query(getTableName(), null, DBHelper.TABLE_ID + "=?", new String[]{id + ""}, null, null, null);
        if (cursor != null) {
            if (cursor.moveToNext()) {
                return fillInstance(cursor);
            }
        }
        return null;
    }

    /**
     * 填充实例
     *
     * @param cursor
     * @return
     */
    public M fillInstance(Cursor cursor) {

        //取到实例
        M instance = getInstance();
        //拿到字段
        Field[] fields = instance.getClass().getDeclaredFields();
        for (Field item : fields) {
            item.setAccessible(true);
            try {
                //拿到数据库里的值
                //1.取注解
                Column itemAnnotation = item.getAnnotation(Column.class);
                if (itemAnnotation != null) {
                    //取得注解的表字段名
                    String columnName = itemAnnotation.value();
                    //通过表的字段名去取数据
                    String value = cursor.getString(cursor.getColumnIndex(columnName));
                    Class<?> type = item.getType();
                    String typeName = type.getName();
//                    MyLog.d("DB", "反射赋值：fieldName :" + item.getName() + "    fieldType: " + typeName + "     value:" + value);
                    //给字段设置值
                    if (item.getType() == int.class) {
                        item.set(instance,Integer.parseInt(value));
                    } else if (item.getType() == long.class) {
                        item.set(instance, Long.parseLong(value));
                    } else if (item.getType() == boolean.class) {
                        item.setBoolean(instance, Boolean.parseBoolean(value));
                    } else {

                        item.set(instance, value);//注意只能设置包装类型  如Integer 不能设置int...基本数据类型
                    }
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
        return instance;
    }

    /**
     * 3.如何将实体中的数据设置给表
     * 填充Values
     *
     * @param m
     * @return
     */
    public ContentValues fillConstantValues(M m) {

        ContentValues values = new ContentValues();
        try {
            //反射所有的字段
            Field[] fields = m.getClass().getDeclaredFields();
            for (Field item : fields) {
                //暴力反射
                item.setAccessible(true);
                //拿注解
                Column itemAnnotation = item.getAnnotation(Column.class);
                if (itemAnnotation != null) {
                    //判断是否为主键，如果是则不设置值
                    ID id = item.getAnnotation(ID.class);
                    if (id != null) {
                        if (!id.autoIncrement()) {//不是主键才设值

                            putValues(m, values, item, itemAnnotation);
                        } else {
                        }
                    } else {
                        putValues(m, values, item, itemAnnotation);


                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return values;
    }

    /**
     *
     * @param m
     * @param values
     * @param item
     * @param itemAnnotation
     * @throws IllegalAccessException
     */
    public void putValues(M m, ContentValues values, Field item, Column itemAnnotation) throws IllegalAccessException {
        //取到注解的值，也就是数据库的字段名
        String key = itemAnnotation.value();
        //取得字段的值
        Object value = item.get(m);

        if(Tools.isEmpty(value+"")){
            values.put(key, "");
        }else{

            values.put(key, value + "");
        }
    }

    /**
     * 1.表名的获取(也就是在bean上加入注解，注解)
     * 通过注解拿到表名
     *
     * @return
     */
    public String getTableName() {
        //1.取得实例
        M instance = getInstance();
        //2.取表名的注解
        TableName annotation = instance.getClass().getAnnotation(TableName.class);
        //3.判断是否拿到注解
        if (annotation != null) {
            //取得注解的名字（即表名）
            String value = annotation.value();
            return value;
        }
        return null;
    }

    /**
     * 通过反射得到实例（取得父类的泛型得到实例 ）
     *
     * @return
     */
    public M getInstance() {
        //1.取得当前运行的clss（传入M 的类）
        Class clazz = getClass();
        //2.取得父类的类型（也就是本类）
        Type superclass = clazz.getGenericSuperclass();
        //3.判断本类是否支持泛型
        if (superclass instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) superclass).getActualTypeArguments();
            //取得第一个就是实际类型
            Type actualTypeArgument = actualTypeArguments[0];
            //强转成字节码
            Class c = (Class) actualTypeArgument;
            //得到实例
            try {
                return (M) c.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return null;
    }

    /**
     * 4.如何获取主键的内容（通过属性上的注解）
     *
     * @param m
     * @return
     */
    public String getId(M m) {
        Field[] fields = m.getClass().getDeclaredFields();
        for (Field item : fields) {
            item.setAccessible(true);
            //取得id的注解
            ID id = item.getAnnotation(ID.class);
            if (id != null) {

                try {
                    return item.get(m) + "";
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    @Override
    public boolean isExists(Serializable value) {
        Cursor cursor = db.query(getTableName(), null, getQueryField() + "=?", new String[]{value + ""}, null, null, null);
        //取查询的字段
        if(cursor!=null){
            if(cursor.moveToNext()){
                cursor.close();
                return true;
            }
        }

        return false;
    }

    /**
     * 根据有注解的查询字段查询list
     *
     * @param value
     * @return
     */
    @Override
    public List<M> findListByQuery(Serializable value) {

        Cursor cursor = db.query(getTableName(), null, getQueryField() + "=?", new String[]{value + ""}, null, null, null);
        if (cursor != null) {
            List<M> result = new ArrayList<M>();
            while (cursor.moveToNext()) {
                M instance = fillInstance(cursor);
                result.add(instance);
            }
            cursor.close();
            return result;
        }
        return null;

    }
    /**
     * 根据有注解的查询字段查询list
     *
     * @param value
     * @return
     */
    @Override
    public M findByQuery(Serializable value) {

        Cursor cursor = db.query(getTableName(), null, getQueryField() + "=?", new String[]{value + ""}, null, null, null);
        if (cursor != null) {

            if (cursor.moveToNext()) {
                M instance = fillInstance(cursor);
                cursor.close();
                return instance;
            }

            cursor.close();
            return null;
        }
        return null;

    }

    /**
     * 取得有注解查询的字段名称(注解名称为  Where)
     * @return
     */
    public String getQueryField(){
       M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            Where where = item.getAnnotation(Where.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(where!=null&&column!=null){
                if(where.isQuery()){
//                    MyLog.i(TAG, "返回查询条件的字段： " + column.value());
                    //返回表列的名称
                    return column.value();
                }
            }
        }
        return null;
    }

    /**
     * 取得有注解查询的字段(注解名称为：Name1)
     * @return
     */
    public String getQueryField1(){
        M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            Name1 name1 = item.getAnnotation(Name1.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(name1!=null&&column!=null){
                if(name1.isQuery()){
                    MyLog.i(TAG, "返回查询条件  name1      的字段： " + column.value());
                    return column.value();
                }
            }
        }
        return null;
    }

    /**
     * 取得有注解查询的字段(注解名称为：Count1)
     * @return
     */
    public String getQueryCountField1(){
        M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            Count1 count = item.getAnnotation(Count1.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(count!=null&&column!=null){
               if(count.isQuery()){

                   return column.value();
               }
            }
        }
        return null;
    }
    /**
     * 取得有注解查询的字段(注解名称为：Count1)
     * @return
     */
    public String getQueryCountField2(){
        M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            Count2 count = item.getAnnotation(Count2.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(count!=null&&column!=null){
               if(count.isQuery()){

                   return column.value();
               }
            }
        }
        return null;
    }

    /**
     * 取得有注解查询的字段(注解名称为： Name2)
     * @return
     */
    public String getQueryField2(){
        M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            Name2 name2 = item.getAnnotation(Name2.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(name2!=null&&column!=null){
                if(name2.isQuery()){
                    MyLog.i(TAG, "返回查询条件  name2      的字段： " + column.value());
                    return column.value();
                }
            }
        }
        return null;
    }


    /**
     * 分页加载数据
     * @param value  查询条件
     * @param startIndex  开始的索引
     * @param maxNumber 加载的条数
     * @return
     */
    @Override
    public List<M> findByLimit(Serializable value, Serializable startIndex, Serializable maxNumber){
        String sql = "select * from " + getTableName() + " where "+getQueryField()+"=?"+" order by "+getOrderByField()+" desc" +" limit ? "+" offset ?";
//        String sql = "select * from " + getTableName() + " where "+getQueryField()+"=?" +" limit ? "+" offset ?";
        Cursor cursor = db.rawQuery(sql, new String[] {value+"",maxNumber+"",startIndex+""});
        if (cursor != null) {
            List<M> result = new ArrayList<M>();
            while (cursor.moveToNext()) {
                M instance = fillInstance(cursor);
                result.add(instance);
            }
            cursor.close();
            return result;
        }
        return null;
    }    /**
     * 分页加载数据
     * @param value  查询条件
     * @return
     */
    @Override
    public List<M> findLastData(Serializable value){
        String sql = "select * from " + getTableName() + " where "+getQueryField()+"=?"+" order by "+getOrderByField()+" desc" ;
        Cursor cursor = db.rawQuery(sql, new String[] {value+""});
        if (cursor != null) {
            List<M> result = new ArrayList<M>();
            if (cursor.moveToNext()) {
                M instance = fillInstance(cursor);
                result.add(instance);
                cursor.close();
            }
            return result;
        }
        return null;
    }

    public String getOrderByField(){
        M m =  getInstance();
        Field[] fields = m.getClass().getDeclaredFields();
        for(Field item: fields){
            //取得条件字段的注解
            OrderBy orderBy = item.getAnnotation(OrderBy.class);
            //取得表列的注解
            Column column = item.getAnnotation(Column.class);
            if(orderBy!=null&&column!=null){
                if(orderBy.isQuery()){
                    MyLog.i(TAG, "返回排序的字段 orderBy " + column.value());
                    return column.value();
                }
            }
        }
        return null;
    }

    @Override
    public int getCount() {
        int count = 0;
        Cursor cursor = db.query(getTableName(),null,null,null,null,null,null);

        try {
            if(cursor != null){
                if(cursor.moveToNext()){
                    count =  cursor.getCount();
                }
                cursor.close();
            }
        } finally {
            cursor.close();
        }
        return count;
    }
}
